// React基础 - 解决组件频繁更新


// 方法一
// shouldComponentUpdate 该方法较为繁琐，也不太可能在代码里对比状态的每一个属性
class Comment extends React.Component {

  shouldComponentUpdate (nextProps) {
    // nextProps是接下来的新状态，被改变之后的状态
    // 在shouldComponentUpdate生命周期内对比改变之后的状态与之前额状态是否一致
    if(nextProps.data.body === this.props.data.body &&
      nextProps.data.author === this.props.data.author) {
        return false;
    }
    return true;
  }

  render () {
    // 打印4次
    console.log('Comment render')
    return (
      <div>
        <p>{this.props.data.body}</p>
        <p>-- {this.props.data.author}</p>
      </div>
    )
  }
}

// 方法二
// 避免组件频繁更新2 - PureComponent 
// 更换继承类为PureComponent，PureComponent的原理是内置shouldComponentUpdate并对shouldComponentUpdate做了一定扩展

// 写到这里会发现，控制台并没有停止打印 “Comment render”，依然保持每一秒打印一次
// 这是因为PureComponent只做浅比较，不会递归比较属性，在对比对象的时候只会比较对象的引用，或者只比较最外层属性
// 我们这里的每一次 setState 都是对引用的更新，所以每一次对比上一次状态，永远都是新的数据，因此Comment组件会一直render
// 所以在使用PureComponent时尽量避免对象类型数据，尽可能只用在值类型数据，或者使用一层属性的对象

class Comment extends React.PureComponent {
  render () {
    // 每秒打印2次
    console.log('Comment render')
    return (
      <div>
        <p>{this.props.data.body}</p>
        <p>-- {this.props.data.author}</p>
      </div>
    )
  }
}


// 避免组件频繁更新3 - React.memo v16.6.0后的版本才有
// memo是一个高阶组件，是一个函数，接收一个组件返回一个新组件
// 类似PureComponent只做浅比较，解决了函数型组件没有PureComponent功能的问题
const Comment = React.memo(function (props) {
  // 打印2次
  console.log('Comment render')
  return (
    <div>
      <p>{props.body}</p>
      <p>-- {props.author}</p>
    </div>
  )
})


// PureComponent通过props和state的浅对比来实现shouldComponentUpdate()。除此之外和Component几乎完全相同了。
// PureComponent自带通过props和state的浅对比来实现shouldComponentUpdate()，而Component没有。这样不需要开发者实现shouldComponentUpdate，就可以使用PureComponnent来进行简单判断以提升性能。

// react最重要的步骤，创建虚拟dom，进行diff算法，更新dom树都在此进行。此时就不能更改state了。在 render 里面最好不要更新state



// -------react 组件的生命周期----

// React 生命周期分为三种状态 1. 初始化 2.更新 3.销毁

// 1、getDefaultProps()

// 设置默认的props，也可以用dufaultProps设置组件的默认属性.

// 2、getInitialState()

// 在使用es6的class语法时是没有这个钩子函数的，可以直接在constructor中定义this.state。此时可以访问this.props

// 3、componentWillMount()

// 组件初始化时只调用，以后组件更新不调用，整个生命周期只调用一次，此时可以修改state。

// 4、 render()

// react最重要的步骤，创建虚拟dom，进行diff算法，更新dom树都在此进行。此时就不能更改state了。

// 5、componentDidMount()

// 组件渲染之后调用，只调用一次。

// 更新
// 6、componentWillReceiveProps(nextProps)

// 组件初始化时不调用，组件接受新的props时调用。

// 7、shouldComponentUpdate(nextProps, nextState)

// react性能优化非常重要的一环。组件接受新的state或者props时调用，我们可以设置在此对比前后两个props和state是否相同，如果相同则返回false阻止更新，因为相同的属性状态一定会生成相同的dom树，这样就不需要创造新的dom树和旧的dom树进行diff算法对比，节省大量性能，尤其是在dom结构复杂的时候

// 8、componentWillUpdata(nextProps, nextState)

// 组件初始化时不调用，只有在组件将要更新时才调用，此时可以修改state

// 9、render()

// 组件渲染

// 10、componentDidUpdate()

// 组件初始化时不调用，组件更新完成后调用，此时可以获取dom节点。

// 卸载
// 11、componentWillUnmount()

// 组件将要卸载时调用，一些事件监听和定时器需要在此时清除。

// react 的 合成事件
// SyntheticEvent